package com.totem.order.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.totem.base.constants.CommonConstants;
import com.totem.base.constants.ErrorCode;
import com.totem.base.enums.*;
import com.totem.base.exception.BaseException;
import com.totem.base.model.PageVO;
import com.totem.base.mybatis.UserIdContext;
import com.totem.base.util.DateUtils;
import com.totem.customer.mapper.TCustomerMapper;
import com.totem.customer.mapper.TMemberMapper;
import com.totem.customer.model.TCustomers;
import com.totem.customer.model.TMembers;
import com.totem.order.mapper.*;
import com.totem.order.model.*;
import com.totem.order.service.ITWalletService;
import com.totem.order.vo.*;
import com.totem.product.mapper.TSubscribeMapper;
import com.totem.product.model.TSubscribe;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TWalletServiceImpl extends ServiceImpl<TWalletMapper, TWallets> implements ITWalletService {
    @Autowired
    private TCustomerMapper tCustomerMapper;
    @Autowired
    private TMemberMapper tMemberMapper;
    @Autowired
    private TWalletMapper tWalletMapper;
    @Autowired
    private TWalletJournalMapper tWalletJournalMapper;
    @Autowired
    private TCollectionJournalMapper tCollectionJournalMapper;
    @Autowired
    private TFundOrderItemMapper tFundOrderItemMapper;
    @Autowired
    private TGoodsOrderItemMapper tGoodsOrderItemMapper;
    @Autowired
    private TRechargeOrderItemMapper tRechargeOrderItemMapper;
    @Autowired
    private TSubscribeOrderItemMapper tSubscribeOrderItemMapper;
    @Autowired
    private TWithdrawOrderItemMapper tWithdrawOrderItemMapper;
    @Autowired
    private TOrderMapper tOrderMapper;
    @Autowired
    private TSubscribeMapper tSubscribeMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private Executor asyncExecutor;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public GoodsPaymentVO goodsPayment(GoodsPaymentVO vo) {
        Long orderId = Long.valueOf(vo.getOrderNo());
        Long customerId = UserIdContext.getUserId();
        if(customerId==null){
            log.warn("当前客户不存在");
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }
        TCustomers me = tCustomerMapper.selectById(customerId);
        if(me==null){
            log.warn("Id为[{}]的客户不存在", customerId);
            throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER);
        }
        if(StateEnum.isStop(me.getState())){
            log.warn("Id为[{}]的客户已被封号", customerId);
            throw new BaseException(ErrorCode.STOPPED_CUSTOMER);
        }
        TOrders tOrders = tOrderMapper.selectById(orderId);
        if(tOrders==null){
            log.warn("订单编号[{}]不存在", orderId);
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER);
        }
        if(!customerId.equals(tOrders.getCustomerId())){
            log.warn("订单[{}]不是当前客户[{}]的", orderId, customerId);
            throw new BaseException(ErrorCode.ORDER_NOT_BELONG_CUSTOMER);
        }
        if(tOrders.getPaymentState().equalsIgnoreCase(PaymentStateEnum.CANCEL.getCode())){
            log.warn("订单[{}]已取消", orderId);
            throw new BaseException(ErrorCode.ORDER_CANCEL);
        }
        if(tOrders.getPaymentState().equalsIgnoreCase(PaymentStateEnum.DISABLED.getCode())){
            log.warn("订单[{}]已失效", orderId);
            throw new BaseException(ErrorCode.ORDER_DISABLE);
        }
        if(tOrders.getPaymentState().equalsIgnoreCase(PaymentStateEnum.FINISHED.getCode())){
            log.warn("订单[{}]已支付", orderId);
            throw new BaseException(ErrorCode.ORDER_FINISHED);
        }
        LambdaQueryWrapper<TGoodsOrderItems> goodsOrderItemQuery = new LambdaQueryWrapper<>();
        goodsOrderItemQuery.eq(TGoodsOrderItems::getOrderId, orderId);
        TGoodsOrderItems goodsOrderItems = tGoodsOrderItemMapper.selectOne(goodsOrderItemQuery);
        if(goodsOrderItems==null){
            log.warn("商品订单项[{}]不存在", orderId);
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER_ITEM);
        }
        String currency = goodsOrderItems.getCurrency();

        TWallets myWallet = tWalletMapper.selectById(customerId);
        if(myWallet==null){
            log.warn("客户[{}]钱包未找到", customerId);
            throw new BaseException(ErrorCode.NOT_EXIST_WALLET);
        }
        BigDecimal amount = tOrders.getAmount();
        BigDecimal beforeBalance = null;
        if(CurrencyEnum.USDT.getCode().equalsIgnoreCase(currency)){
            beforeBalance = myWallet.getUsdt();
            if(myWallet.getUsdt().compareTo(amount)<0) {
                log.warn("客户[{}]的USDT余额不足", customerId);
                throw new BaseException(ErrorCode.INSUFFICIENT_BALANCE);
            }
        }
        if(CurrencyEnum.USDO.getCode().equalsIgnoreCase(currency)){
            beforeBalance = myWallet.getUsdo();
            if(myWallet.getUsdo().compareTo(amount)<0) {
                log.warn("客户[{}]的USDO余额不足", customerId);
                throw new BaseException(ErrorCode.INSUFFICIENT_BALANCE);
            }
        }

        Date now = new Date();
        String paymentTime = DateUtils.formatDate(now, CommonConstants.DEFAULT_DATETIME_FORMAT);
        TOrders orderUpdate = TOrders.builder()
                .id(orderId)
                .paymentState(PaymentStateEnum.FINISHED.getCode())
                .paymentTime(now)
                .build();
        tOrderMapper.updateById(orderUpdate);

        BigDecimal afterBalance = beforeBalance.subtract(amount);
        TWallets updateWallet = TWallets.builder()
                .customerId(customerId)
                .build();
        if(CurrencyEnum.USDT.getCode().equalsIgnoreCase(currency)){
            updateWallet.setUsdt(afterBalance);
        }
        if(CurrencyEnum.USDO.getCode().equalsIgnoreCase(currency)){
            updateWallet.setUsdo(afterBalance);
        }
        tWalletMapper.updateById(updateWallet);

        TWalletJournal journal = TWalletJournal.builder()
                .customerId(customerId)
                .orderId(tOrders.getId())
                .beforeBalance(beforeBalance)
                .journalType(JournalTypeEnum.GOODS_ORDER.getCode())
                .amount(amount)
                .afterBalance(afterBalance)
                .charges(BigDecimal.ZERO)
                .currency(currency)
                .direction(DirectionEnum.CREDIT.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .remark("支付商品订单")
                .build();
        tWalletJournalMapper.insert(journal);

        vo.setPaymentState(PaymentStateEnum.FINISHED.getCode());
        vo.setPaymentTime(paymentTime);
        return vo;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SubscribePaymentVO subscribePayment(SubscribePaymentVO vo) {
        Long orderId = Long.valueOf(vo.getOrderNo());
        Long customerId = UserIdContext.getUserId();
        if(customerId==null){
            log.warn("当前客户不存在");
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }
        TCustomers me = tCustomerMapper.selectById(customerId);
        if(me==null){
            log.warn("Id为[{}]的客户不存在", customerId);
            throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER);
        }
        if(StateEnum.isStop(me.getState())){
            log.warn("Id为[{}]的客户已被封号", customerId);
            throw new BaseException(ErrorCode.STOPPED_CUSTOMER);
        }
        TOrders tOrders = tOrderMapper.selectById(orderId);
        if(tOrders==null){
            log.warn("订单[{}]不存在", orderId);
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER);
        }
        if(!customerId.equals(tOrders.getCustomerId())){
            log.warn("订单[{}]不是当前客户[{}]的", orderId, customerId);
            throw new BaseException(ErrorCode.ORDER_NOT_BELONG_CUSTOMER);
        }
        if(tOrders.getPaymentState().equalsIgnoreCase(PaymentStateEnum.DISABLED.getCode())){
            log.warn("订单[{}]已失效", orderId);
            throw new BaseException(ErrorCode.ORDER_DISABLE);
        }
        if(tOrders.getPaymentState().equalsIgnoreCase(PaymentStateEnum.FINISHED.getCode())){
            log.warn("订单[{}]已支付", orderId);
            throw new BaseException(ErrorCode.ORDER_FINISHED);
        }
        LambdaQueryWrapper<TSubscribeOrderItems> subscribeOrderItemQuery = new LambdaQueryWrapper<>();
        subscribeOrderItemQuery.eq(TSubscribeOrderItems::getOrderId, orderId);
        TSubscribeOrderItems subscribeOrderItem = tSubscribeOrderItemMapper.selectOne(subscribeOrderItemQuery);
        if(subscribeOrderItem==null){
            log.warn("认购订单项[{}]不存在", orderId);
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER_ITEM);
        }
        String currency = subscribeOrderItem.getCurrency();
        Date now = new Date();
        String paymentTime = DateUtils.formatDate(now, CommonConstants.DEFAULT_DATETIME_FORMAT);

        // 允许延迟支付半小时
        Date timeout = DateUtils.getAddDate(tOrders.getOrderTime(), Calendar.MINUTE, 30);
        if(now.compareTo(timeout)>0){
            log.warn("订单[{}]已超时失效", orderId);
            throw new BaseException(ErrorCode.PAYMENT_TIMEOUT);
        }
        LambdaQueryWrapper<TSubscribe> subscribeQuery = new LambdaQueryWrapper<>();
        subscribeQuery.eq(TSubscribe::getSubscribeName, subscribeOrderItem.getSubscribeName());
        TSubscribe tSubscribe = tSubscribeMapper.selectOne(subscribeQuery);
        if(tSubscribe==null){
            log.warn("客户[{}]的认购包未找到", customerId);
            throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER_SUBSCRIBE);
        }
        TWallets myWallet = tWalletMapper.selectById(customerId);
        if(myWallet==null){
            log.warn("客户[{}]钱包未找到", customerId);
            throw new BaseException(ErrorCode.NOT_EXIST_WALLET);
        }
        BigDecimal amount = tOrders.getAmount();
        BigDecimal beforeBalance = null;
        if(CurrencyEnum.isUSDT(currency)){
            beforeBalance = myWallet.getUsdt();
            if(myWallet.getUsdt().compareTo(amount)<0) {
                log.warn("客户[{}]的USDT余额不足", customerId);
                throw new BaseException(ErrorCode.INSUFFICIENT_BALANCE);
            }
        }
        if(CurrencyEnum.isUSDO(currency)){
            beforeBalance = myWallet.getUsdo();
            if(myWallet.getUsdo().compareTo(amount)<0) {
                log.warn("客户[{}]的USDO余额不足", customerId);
                throw new BaseException(ErrorCode.INSUFFICIENT_BALANCE);
            }
        }

        TOrders orderUpdate = TOrders.builder()
                .id(orderId)
                .paymentState(PaymentStateEnum.FINISHED.getCode())
                .paymentTime(now)
                .build();
        tOrderMapper.updateById(orderUpdate);

        TSubscribeOrderItems updateOrderItem = TSubscribeOrderItems.builder()
                .id(subscribeOrderItem.getId())
                .returnHandleState(HandleStateEnum.HANDLING.getCode()) // 收益中
                .build();
        tSubscribeOrderItemMapper.updateById(updateOrderItem);

        BigDecimal afterBalance = beforeBalance.subtract(amount);
        TWallets updateWallet = TWallets.builder()
                .customerId(customerId)
                .build();
        if(CurrencyEnum.isUSDT(currency)){
            updateWallet.setUsdt(afterBalance);
        }
        if(CurrencyEnum.isUSDO(currency)){
            updateWallet.setUsdo(afterBalance);
        }
        tWalletMapper.updateById(updateWallet);

        TWalletJournal journal = TWalletJournal.builder()
                .customerId(customerId)
                .orderId(tOrders.getId())
                .journalType(JournalTypeEnum.SUBSCRIBE_ORDER.getCode())
                .beforeBalance(beforeBalance)
                .amount(amount)
                .afterBalance(afterBalance)
                .charges(BigDecimal.ZERO)
                .currency(currency)
                .direction(DirectionEnum.CREDIT.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .remark("支付认购订单")
                .build();
        tWalletJournalMapper.insert(journal);

        TMembers member = tMemberMapper.selectById(customerId);
        TMembers updateMember = TMembers.builder()
                .customerId(customerId)
                .build();

        // 特殊认购可能需要更新待遇等级
        String subscribeLevel = tSubscribe.getSubscribeLevel();
        if(!SubscribeLevelEnum.isNormal(subscribeLevel)){
            int enjoyLevel = member.getEnjoyLevel();
            int subscribeEnjoyLevel = SubscribeLevelEnum.byCode(subscribeLevel).getValue();
            if(enjoyLevel<subscribeEnjoyLevel){
                updateMember.setEnjoyLevel(subscribeEnjoyLevel);
            }
        }

        // 认购投入累计
        updateMember.setInvest(member.getInvest().add(amount));
        tMemberMapper.updateById(updateMember);

        // 计算预估收益
        int subscribeDays = tSubscribe.getSubscribeDays();
        BigDecimal estimatedReturn = amount.add(amount
                .multiply(tSubscribe.getDailyRateReturn())
                .multiply(new BigDecimal(subscribeDays))
                .setScale(CommonConstants.DEFAULT_SCALE, RoundingMode.HALF_UP));

        vo.setReturnDays(subscribeDays);
        vo.setPaymentState(PaymentStateEnum.FINISHED.getCode());
        vo.setEstimatedReturn(estimatedReturn);
        vo.setPaymentTime(paymentTime);
        return vo;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public WithdrawPaymentVO withdrawPayment(WithdrawPaymentVO vo) {
        Date now = new Date();
        String orderNo = vo.getOrderNo();
        if(StringUtils.isBlank(orderNo)){
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER_NO);
        }
        Long orderId = Long.valueOf(orderNo);
        TOrders tOrder = tOrderMapper.selectById(orderId);
        if(tOrder==null){
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER);
        }
        Boolean accept = vo.getAccept();
        if(accept==null){
            throw new BaseException(ErrorCode.REQUIRED_ACCEPT);
        }
        Long customerId = tOrder.getCustomerId();
        TCustomers me = tCustomerMapper.selectById(customerId);
        if(me==null){
            log.warn("Id为[{}]的客户不存在", customerId);
            throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER);
        }
        if(StateEnum.isStop(me.getState())){
            log.warn("Id为[{}]的客户已被封号", customerId);
            throw new BaseException(ErrorCode.STOPPED_CUSTOMER);
        }
        Long currentId = UserIdContext.getUserId();
        if(currentId==null){
            log.warn("登录的客户不存在");
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }
        TCustomers loginCust = tCustomerMapper.selectById(currentId);
        if(loginCust==null){
            log.warn("登录的客户不存在");
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }
        // 只有admin和financial才能操作
        String nickname = loginCust.getNickname();
        if(!CommonConstants.DEFAULT_ADMIN.equalsIgnoreCase(nickname) && !CommonConstants.DEFAULT_FINANCIAL.equalsIgnoreCase(nickname)){
            log.warn("客户[{}]尝试批准提现,被拒绝", customerId);
            throw new BaseException(ErrorCode.CANNOT_ACCESS);
        }
        LambdaQueryWrapper<TWithdrawOrderItems> withdrawQuery = new LambdaQueryWrapper<>();
        withdrawQuery.eq(TWithdrawOrderItems::getOrderId, orderId);
        TWithdrawOrderItems withdrawOrderItem = tWithdrawOrderItemMapper.selectOne(withdrawQuery);
        if(withdrawOrderItem==null){
            log.warn("订单[{}]的订单项不存在", orderId);
            throw new BaseException(ErrorCode.NOT_EXIST_ORDER_ITEM);
        }
        TOrders updateOrder = TOrders.builder()
                .id(orderId)
                .paymentTime(now)
                .build();

        String paymentState = null;
        if(accept){
            paymentState = PaymentStateEnum.FINISHED.getCode();
        }else{
            paymentState = PaymentStateEnum.CANCEL.getCode();
            TWallets wallet = tWalletMapper.selectById(customerId);
            if(wallet==null){
                log.warn("客户[{}]的钱包不存在", customerId);
                throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER);
            }
            BigDecimal amount = tOrder.getAmount();
            BigDecimal before = wallet.getUsdt();
            BigDecimal after = before.add(amount);
            TWallets updateWallet = TWallets.builder()
                    .customerId(customerId)
                    .usdt(after)
                    .build();
            tWalletMapper.updateById(updateWallet);
        }

        updateOrder.setPaymentState(paymentState);
        tOrderMapper.updateById(updateOrder);

        LambdaQueryWrapper<TWalletJournal> journalQuery = new LambdaQueryWrapper<>();
        journalQuery.eq(TWalletJournal::getOrderId, orderId);
        journalQuery.eq(TWalletJournal::getCustomerId, customerId);
        journalQuery.eq(TWalletJournal::getJournalType, JournalTypeEnum.WITHDRAW.getCode());
        journalQuery.eq(TWalletJournal::getJournalState, JournalStateEnum.PENDING.getCode());
        TWalletJournal withdrawJournal = tWalletJournalMapper.selectOne(journalQuery);
        if(withdrawJournal==null){
            log.warn("客户[{}]提现订单[{}]的流水不存在", customerId, orderId);
            throw new BaseException(ErrorCode.NOT_EXIST_WALLET_JOURNAL);
        }

        TWithdrawOrderItems updateItem = TWithdrawOrderItems.builder()
                .id(withdrawOrderItem.getId())
                .build();

        TWalletJournal updateJournal = TWalletJournal.builder()
                .id(withdrawJournal.getId())
                .build();

        if(accept) {
            updateItem.setHandleState(HandleStateEnum.HANDLED.getCode());

            updateJournal.setJournalState(JournalStateEnum.FINISHED.getCode());
            updateJournal.setRemark("接受提现");
            vo.setWithdrawState(HandleStateEnum.HANDLED.getCode());
        }else{
            updateItem.setHandleState(HandleStateEnum.CANCEL.getCode());

            updateJournal.setAmount(BigDecimal.ZERO);
            updateJournal.setCharges(BigDecimal.ZERO);
            updateJournal.setAfterBalance(withdrawJournal.getBeforeBalance());
            updateJournal.setJournalState(JournalStateEnum.CANCEL.getCode());
            updateJournal.setRemark("拒绝提现");
            vo.setWithdrawState(HandleStateEnum.CANCEL.getCode());
        }
        tWithdrawOrderItemMapper.updateById(updateItem);

        tWalletJournalMapper.updateById(updateJournal);

        return vo;
    }

    @Override
    public PageVO<WalletJournalVO> journalPage(WalletJournalPageVO vo) {
        if(StringUtils.isNotBlank(vo.getJournalType())) {
            JournalTypeEnum journalTypeEnum = JournalTypeEnum.byCode(vo.getJournalType());
            if (journalTypeEnum == null) {
                log.warn("流水类型错误,不支持[{}]", vo.getJournalType());
                throw new BaseException(ErrorCode.ILLEGAL_JOURNAL_TYPE);
            }
        }
        if(StringUtils.isNotBlank(vo.getCurrency())){
            CurrencyEnum currencyEnum = CurrencyEnum.byCode(vo.getCurrency());
            if(currencyEnum==null){
                log.warn("币种错误,不支持[{}]", vo.getCurrency());
                throw new BaseException(ErrorCode.ILLEGAL_CURRENCY);
            }
        }

        Long customerId = vo.getCustomerId();
        List<Long> customerIdList = null;
        Map<Long, TCustomers> custMap;
        if(StringUtils.isNotBlank(vo.getNickname())){
            LambdaQueryWrapper<TCustomers> custQuery = new LambdaQueryWrapper<>();
            custQuery.like(TCustomers::getNickname, vo.getNickname());
            custQuery.eq(TCustomers::getState, StateEnum.NORMAL.getCode());
            List<TCustomers> customerList = tCustomerMapper.selectList(custQuery);
            customerIdList = customerList.stream().map(TCustomers::getId).toList();
            custMap = customerList.stream().collect(Collectors.toMap(TCustomers::getId, Function.identity()));
        } else if(customerId!=null){
            TCustomers tCustomers = tCustomerMapper.selectById(customerId);
            if(tCustomers==null){
                throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER);
            }
            customerIdList = List.of(tCustomers.getId());
            custMap = new HashMap<>();
            custMap.put(customerId, tCustomers);
        }else{
            custMap = new HashMap<>();
        }
        List<TCustomers> admList = findAdmList();
        Map<Long, TCustomers> adminMap = admList.stream().collect(Collectors.toMap(TCustomers::getId, Function.identity()));

        Page<TWalletJournal> page = new Page<>();
        if(vo.getCurrent()>0 && vo.getPageSize()>0) {
            page.setCurrent(vo.getCurrent());
            page.setSize(vo.getPageSize());
        }

        Date end = vo.getQueryEndTime();
        Date start = vo.getQueryStartTime();
        LambdaQueryWrapper<TWalletJournal> journalQuery = new LambdaQueryWrapper<>();
        journalQuery.eq(StringUtils.isNotBlank(vo.getJournalType()), TWalletJournal::getJournalType, vo.getJournalType());
        journalQuery.eq(StringUtils.isNotBlank(vo.getCurrency()), TWalletJournal::getCurrency, vo.getCurrency());
        journalQuery.in(!CollectionUtils.isEmpty(customerIdList), TWalletJournal::getCustomerId, customerIdList);
        journalQuery.between(end!=null && start!=null, TWalletJournal::getCreateTime, start, end);
        journalQuery.orderByDesc(TWalletJournal::getUpdateTime);
        Page<TWalletJournal> journalPage = tWalletJournalMapper.selectPage(page, journalQuery);
        List<TWalletJournal> journalList = journalPage.getRecords();
        if(MapUtil.isEmpty(custMap) && !CollectionUtils.isEmpty(journalList)){
            List<Long> customerIdTempList = journalList.stream().map(TWalletJournal::getCustomerId).toList();
            List<TCustomers> custList = tCustomerMapper.selectBatchIds(customerIdTempList);
            Map<Long, TCustomers> custTempMap = custList.stream().collect(Collectors.toMap(TCustomers::getId, Function.identity()));
            custMap.putAll(custTempMap);
        }

        List<WalletJournalVO> journalVOList = journalList.stream().map(journal->{
            TCustomers customer = null;
            if(!MapUtil.isEmpty(custMap)) {
                customer = custMap.get(journal.getCustomerId());
            }
            WalletJournalVO journalVO = new WalletJournalVO();
            BeanUtils.copyProperties(journal, journalVO);
            if(customer!=null) {
                journalVO.setNickname(customer.getNickname());
            }

            String journalType = journalVO.getJournalType();
            if(StringUtils.isNotBlank(journalType)){
                JournalTypeEnum journalTypeEnum = JournalTypeEnum.byCode(journalType);
                if(journalTypeEnum==null){
                    throw new BaseException(ErrorCode.ILLEGAL_OPERATE_TYPE);
                }
                TCustomers manager = adminMap.get(journal.getUpdateBy());
                // 管理员操作时,需要拼接昵称到JournalType中
                if(manager!=null && JournalTypeEnum.ADMIN_OPERATE.getCode().equalsIgnoreCase(journalType)){
                    String tempJournalType = String.format("%s(%s)", journalTypeEnum.getCn(), manager.getNickname());
                    journalVO.setJournalTypeCn(tempJournalType);
                }else{
                    journalVO.setJournalTypeCn(journalTypeEnum.getCn());
                }
            }

            Date ct = journal.getCreateTime();
            String ctStr = DateUtils.formatDate(ct, CommonConstants.DEFAULT_DATETIME_FORMAT);
            journalVO.setJournalDate(ctStr);
            return journalVO;
        }).toList();

        PageVO<WalletJournalVO> pageVO = new PageVO<>();
        pageVO.setTotal(page.getTotal());
        pageVO.setList(journalVOList);
        return pageVO;
    }

    @Override
    public PageVO<CollectionJournalVO> collectionJournalPage(CollectionJournalPageVO vo) {
        if(StringUtils.isNotBlank(vo.getCryptoCurrency())) {
            CryptoCurrencyEnum cryptoCurrencyEnum = CryptoCurrencyEnum.byCode(vo.getCryptoCurrency());
            if (cryptoCurrencyEnum == null) {
                log.warn("归集流水类型错误,不支持[{}]", vo.getCryptoCurrency());
                throw new BaseException(ErrorCode.ILLEGAL_CRYPTO_CURRENCY);
            }
        }

        List<Long> customerIdList = null;
        Map<Long, String> custNicknameMap;
        if(StringUtils.isNotBlank(vo.getNickname())){
            LambdaQueryWrapper<TCustomers> custQuery = new LambdaQueryWrapper<>();
            custQuery.like(TCustomers::getNickname, vo.getNickname());
            custQuery.eq(TCustomers::getState, StateEnum.NORMAL.getCode());
            List<TCustomers> customerList = tCustomerMapper.selectList(custQuery);
            customerIdList = customerList.stream().map(TCustomers::getId).toList();
            custNicknameMap = customerList.stream().collect(Collectors.toMap(TCustomers::getId, TCustomers::getNickname));
        }else{
            custNicknameMap = new HashMap<>();
        }

        Page<TCollectionJournal> page = new Page<>();
        if(vo.getCurrent()>0 && vo.getPageSize()>0) {
            page.setCurrent(vo.getCurrent());
            page.setSize(vo.getPageSize());
        }

        Date end = vo.getQueryEndTime();
        Date start = vo.getQueryStartTime();
        LambdaQueryWrapper<TCollectionJournal> journalQuery = new LambdaQueryWrapper<>();
        journalQuery.eq(StringUtils.isNotBlank(vo.getCryptoCurrency()), TCollectionJournal::getCryptoCurrency, vo.getCryptoCurrency());
        journalQuery.in(!CollectionUtils.isEmpty(customerIdList), TCollectionJournal::getCustomerId, customerIdList);
        journalQuery.between(end!=null && start!=null, TCollectionJournal::getCreateTime, start, end);
        journalQuery.orderByDesc(TCollectionJournal::getUpdateTime);
        Page<TCollectionJournal> journalPage = tCollectionJournalMapper.selectPage(page, journalQuery);
        List<TCollectionJournal> journalList = journalPage.getRecords();
        if(MapUtil.isEmpty(custNicknameMap) && !CollectionUtils.isEmpty(journalList)){
            List<Long> customerIdTempList = journalList.stream().map(TCollectionJournal::getCustomerId).toList();
            List<TCustomers> custList = tCustomerMapper.selectBatchIds(customerIdTempList);
            Map<Long, String> custNicknameTempMap = custList.stream().collect(Collectors.toMap(TCustomers::getId, TCustomers::getNickname));
            custNicknameMap.putAll(custNicknameTempMap);
        }

        List<CollectionJournalVO> journalVOList = journalList.stream().map(journal->{
            String nickname = null;
            if(!MapUtil.isEmpty(custNicknameMap)) {
                nickname = custNicknameMap.get(journal.getCustomerId());
            }
            CollectionJournalVO journalVO = new CollectionJournalVO();
            BeanUtils.copyProperties(journal, journalVO);
            journalVO.setNickname(nickname);

            Date ct = journal.getCreateTime();
            String ctStr = DateUtils.formatDate(ct, CommonConstants.DEFAULT_DATETIME_FORMAT);
            journalVO.setJournalDate(ctStr);
            return journalVO;
        }).toList();

        PageVO<CollectionJournalVO> pageVO = new PageVO<>();
        pageVO.setTotal(page.getTotal());
        pageVO.setList(journalVOList);
        return pageVO;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean updateWalletUsdt(UpdateWalletUSDTVO vo) {
        Long customerId = vo.getCustomerId();
        if(customerId==null || customerId<=0){
            throw new BaseException(ErrorCode.REQUIRED_CUSTOMER_ID);
        }
        Long currentId = UserIdContext.getUserId();
        if(currentId==null){
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }
        String direction = vo.getDirection();
        DirectionEnum directionEnum = DirectionEnum.byCode(direction);
        if(directionEnum==null){
            throw new BaseException(ErrorCode.ILLEGAL_DIRECTION);
        }
        BigDecimal amount = vo.getAmount();
        if(amount==null || amount.compareTo(BigDecimal.ZERO)<=0){
            throw new BaseException(ErrorCode.TX_AMOUNT_ERROR);
        }
        TCustomers currentUser = tCustomerMapper.selectById(currentId);
        if(currentUser==null){
            log.warn("Id为[{}]的客户不存在", currentId);
            throw new BaseException(ErrorCode.NOT_EXIST_CUSTOMER);
        }
        // 只有admin和financial才能操作
        String nickname = currentUser.getNickname();
        if(!CommonConstants.DEFAULT_ADMIN.equalsIgnoreCase(nickname) && !CommonConstants.DEFAULT_FINANCIAL.equalsIgnoreCase(nickname)){
            log.warn("客户[{}]尝试批准提现,被拒绝", customerId);
            throw new BaseException(ErrorCode.CANNOT_ACCESS);
        }
        String currentCustname = currentUser.getNickname();
        TWallets wallet = tWalletMapper.selectById(customerId);
        if(wallet==null){
            throw new BaseException(ErrorCode.NOT_EXIST_WALLET);
        }
        BigDecimal before = wallet.getUsdt();
        BigDecimal after = null;
        if(DirectionEnum.isCredit(direction)){
            after = before.subtract(amount);
        }
        if(DirectionEnum.isDebit(direction)){
            after = before.add(amount);
        }
        TWallets update = TWallets.builder()
                .customerId(customerId)
                .usdt(after)
                .build();
        tWalletMapper.updateById(update);

        TWalletJournal journal = TWalletJournal.builder()
                .customerId(customerId)
                .journalType(JournalTypeEnum.ADMIN_OPERATE.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .beforeBalance(before)
                .amount(amount)
                .charges(BigDecimal.ZERO)
                .afterBalance(after)
                .direction(direction)
                .currency(CurrencyEnum.USDT.getCode())
                .remark(String.format("管理员[%s]修改USDT余额", currentCustname))
                .build();

        tWalletJournalMapper.insert(journal);
        return true;
    }

    private List<TCustomers> findAdmList(){
        LambdaQueryWrapper<TCustomers> admQuery = new LambdaQueryWrapper<>();
        admQuery.in(TCustomers::getNickname,
                CommonConstants.DEFAULT_ADMIN,
                CommonConstants.DEFAULT_FINANCIAL,
                CommonConstants.DEFAULT_OPERATION);
        return tCustomerMapper.selectList(admQuery);
    }
}
